package mx.itesm.gda.clever.ui;

import java.io.ByteArrayInputStream;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import cml.analyzing.Analyzer;
import cml.parsing.ParsingScanner;
import cml.parsing.parser;
import cml.parsing.tree.BoolNode;
import cml.parsing.tree.CallNode;
import cml.parsing.tree.DeclNode;
import cml.parsing.tree.ExpNode;
import cml.parsing.tree.ForNode;
import cml.parsing.tree.FuncDeclNode;
import cml.parsing.tree.IfNode;
import cml.parsing.tree.NumNode;
import cml.parsing.tree.OpNode;
import cml.parsing.tree.ParamNode;
import cml.parsing.tree.ReturnNode;
import cml.parsing.tree.StmtNode;
import cml.parsing.tree.SynNode;
import cml.parsing.tree.TextNode;
import cml.parsing.tree.TypeNode;
import cml.parsing.tree.UNode;
import cml.parsing.tree.VarDeclNode;
import cml.parsing.tree.VarNode;
import cml.parsing.tree.WhileNode;
import cml.scanning.Scanner;

public class SyntaxTreeView extends ViewPart {
	
	public static final String ID = "mx.itesm.gda.clever.ui.SyntaxTreeView";
	
	private Tree tree;
	
	private String[] columnHeaders = {
			LocalizedMessages.SyntaxTreeView_itemHeader,
			LocalizedMessages.SyntaxTreeView_lineHeader
	};
	private int[] columnStyles = {
			SWT.LEFT, SWT.RIGHT
	};
	private int[] columnWidths = {
			200, 25
	};
	
	private TreeItem treeRoot;
	
	@Override
	public void createPartControl(final Composite parent) {
		
		// Set up tree.
		
		tree = new Tree(parent, SWT.NONE);
		tree.setHeaderVisible(true);
		
		for (int i = 0; i < columnHeaders.length; i++) {
			final TreeColumn column = new TreeColumn(tree, columnStyles[i]);
			column.setText(columnHeaders[i]);
			column.setWidth(columnWidths[i]);
		}
		
		treeRoot = new TreeItem(tree, SWT.NONE);
		treeRoot.setText("compilation-unit");
	}
	
	public void parse(final ITextEditor editor) throws Exception {
		final IDocumentProvider provider = editor.getDocumentProvider();
		if (provider == null) return;
		
		final IDocument document = provider.getDocument(editor.getEditorInput());
		
		parse(document);
	}
	
	private void parse(final IDocument document) throws Exception {
		final String text = document.get();
		
		final Scanner scanner = new Scanner(new ByteArrayInputStream(text
				.getBytes()));
		final ParsingScanner ps = new ParsingScanner(scanner);
		final parser p = new parser(ps);
		
		p.parse();
		ErrorsView.setErrors(p.getSynErrors(), true);
		
		final SynNode syntaxTree = p.getTree();
		treeRoot.removeAll();
		addNode(syntaxTree, treeRoot);
		
		Analyzer sem = new Analyzer();
		sem.analyze(syntaxTree);
		ErrorsView.addErrors(sem.getSemErr(), false);
	}
	
	@SuppressWarnings("unchecked")
	private void addNode(SynNode node, final TreeItem parent) {
		while (node != null) {
			final TreeItem item = new TreeItem(parent, SWT.NONE);
			if (node instanceof DeclNode) {
				final DeclNode temp = (DeclNode) node;
				if (temp instanceof VarDeclNode) {
					item.setText("declaraci\u00f3n-variable: " + temp.getName());
				} else if (temp instanceof FuncDeclNode) {
					item.setText("declaraci\u00f3n-funcion: " + temp.getName());
				} else if (node instanceof ParamNode) {
					item.setText("par\u00e1metro: " + temp.getName());
				}
			} else if (node instanceof StmtNode) {
				if (node instanceof IfNode) {
					item.setText("si");
				} else if (node instanceof ForNode) {
					item.setText("para");
				} else if (node instanceof WhileNode) {
					item.setText("mientras");
				} else if (node instanceof ReturnNode) {
					item.setText("regresa");
				}
			} else if (node instanceof ExpNode) {
				if (node instanceof OpNode) {
					final OpNode temp = (OpNode) node;
					item.setText("operador: " + temp.getName());
					// } else if (node instanceof IdNode) {
					// final IdNode temp = (IdNode) node;
					// item.setText("identificador: " + temp.getName());
				} else if (node instanceof TypeNode) {
					final TypeNode temp = (TypeNode) node;
					item.setText("tipo: " + temp.getName());
				} else if (node instanceof NumNode) {
					final NumNode<? extends Number> temp = (NumNode) node;
					final Number value = temp.getValue();
					if (value instanceof Integer) {
						final Integer v = (Integer) value;
						item.setText("entero: " + v);
					} else if (value instanceof Double) {
						final Double v = (Double) value;
						item.setText("decimal: " + v);
					}
				} else if (node instanceof BoolNode) {
					final BoolNode temp = (BoolNode) node;
					item.setText("booleano: " + temp.getValue());
				} else if (node instanceof TextNode) {
					final TextNode temp = (TextNode) node;
					item.setText("texto: " + temp.getValue());
				} else if (node instanceof VarNode) {
					final VarNode temp = (VarNode) node;
					item.setText("variable: " + temp.getName());
				} else if (node instanceof CallNode) {
					final CallNode temp = (CallNode) node;
					item.setText("llamada: " + temp.getName());
				}
			}
			
			item.setText(1, Integer.toString(node.getLineNo() + 1));
			
			for (int i = 0; i < node.getChildCount(); i++) {
				addNode(node.getChild(i), item);
			}
			node = node.getSibling();
		}
		parent.setExpanded(true);
	}
	
	@Override
	public void setFocus() {
		tree.setFocus();
	}
	
}
